package com.zhb.core.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

/**
 * 这是一个工具类，主要用于实现将文件上传到ftp服务器和从ftp服务器下载文件的功能。<br/>
 * 注意：<br>
 * 1、本程序依赖以下jar包：<br/>
 * commons-io-2.1.jar<br/>
 * commons-logging-1.1.1.jar<br/>
 * commons-net-1.4.1.jar<br/>
 * jakarta-oro-2.0.8.jar<br/>
 * log4j-1.2.16.jar<br/>
 * 2、如果文件名包含中文的文件直接上传到ftp服务器或者是从ftp服务器下载都会失败，ftp服务器<br/>
 * 端的目录也不能包含中文<br/>
 * 3、与spring进行整合,只需要按以下方式配置，设置进行ftp通信必须的5个参数即可:<br/>
 * 配置一个bean ，然后配置以下5个参数<br/>
 * ftpHost: ip<br/>
 * ftpPort: 端口<br/>
 * ftpUsername: 用户名<br/>
 * ftpPassword: 密码</property><br/>
 * webUrl:返回上传到ftp服务器的图片对应于web服务器地址的前半部分，例如http://192.158.100.105:81/files
 * z这个参数主要是为了给fckeditor返回图片路径时使用。
 *
 * @ClassName: FtpUtil
 * @Description: ftp文件上传的核心工具类
 * @author zhb
 * @date 2016年2月26日 上午11:35:50
 */
@SuppressWarnings("all")
public class FtpUtil {

	/** ftp服务器主机地址（或域名） */
	private String ftpHost;
	/** ftp服务器的端口号 */
	private int ftpPort;
	/** ftp服务器用户名 */
	private String ftpUsername;
	/** ftp服务器认证密码 */
	private String ftpPassword;
	/** web服务器的url,格式为http://域名:端口号/web项目名（保存图片的web项目名） */
	private String webUrl;

	public String getWebUrl() {
		return webUrl;
	}

	public void setWebUrl(String webUrl) {
		this.webUrl = webUrl;
	}

	public String getFtpHost() {
		return ftpHost;
	}

	public void setFtpHost(String ftpHost) {
		this.ftpHost = ftpHost;
	}

	public int getFtpPort() {
		return ftpPort;
	}

	public void setFtpPort(int ftpPort) {
		this.ftpPort = ftpPort;
	}

	public String getFtpUsername() {
		return ftpUsername;
	}

	public void setFtpUsername(String ftpUsername) {
		this.ftpUsername = ftpUsername;
	}

	public String getFtpPassword() {
		return ftpPassword;
	}

	public void setFtpPassword(String ftpPassword) {
		this.ftpPassword = ftpPassword;
	}

	/**
	 * 初始化工作，连接ftp服务器
	 */
	private FTPClient init() {
		return ftpConnect(ftpHost, ftpPort, ftpUsername, ftpPassword);
	}

	/**
	 * 连接到FTP服务器
	 * 
	 * @param host
	 *            FTP地址
	 * @param port
	 *            端口号
	 * @param username
	 *            用户名
	 * @param password
	 *            密码
	 */
	public FTPClient ftpConnect(String host, int port, String username,
			String password) {
		FTPClient ftpClient = new FTPClient();
		try {
			ftpClient.connect(host, port);
			ftpClient.setControlEncoding("UTF-8");
			int reply = ftpClient.getReplyCode();
			if (FTPReply.isPositiveCompletion(reply)) {
				if (ftpClient.login(username, password)) {
					System.out.println("Successful login!");
				} else {
					System.out.println("fail to login!");
				}
			}
		} catch (Exception e) {
			System.out.println("Failure connection!");
			e.printStackTrace();
		}
		return ftpClient;
	}

	/**
	 * 从本地上传单个文件到ftp服务器
	 * 
	 * @param localName
	 *            本地要上传到ftp服务器上的文件（包含路径和文件名）
	 * @param ftpPath
	 *            所要放于ftp的路径(放在ftp服务器的哪个文件夹)
	 * @param newName
	 *            ftp服务器端保存使用的文件名
	 */
	public void ftpUpload(String localName, String ftpPath, String newName) {
		FTPClient ftpClient = init();// 初始化
		File srcFile = new File(localName);
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(srcFile);
			// 改变工作目录到所需要的路径下
			if (ftpPath != null && ftpPath.trim().length() > 0) {
				ftpClient.makeDirectory(ftpPath);
				ftpClient.changeWorkingDirectory(ftpPath);
			}
			ftpClient.setBufferSize(1024);
			ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
			ftpClient.storeFile(newName, fis);
		} catch (FileNotFoundException e1) {
			System.out.println("Failed to upload!");
			throw new RuntimeException(e1);
		} catch (IOException e2) {
			System.out.println("Failed to upload!");
			throw new RuntimeException(e2);
		} finally {
			try {
				if (fis != null) {
					fis.close();
				}
				ftpDisConnect(ftpClient);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		FtpUtil ftpUtil = new FtpUtil();
		ftpUtil.setFtpHost("127.0.0.1");
		ftpUtil.setFtpPort(21);
		ftpUtil.setFtpUsername("ftpuser");
		ftpUtil.setFtpPassword("ftppass");
		ftpUtil.setWebUrl("http://192.168.102.8:81/ftpserver");
		long a = System.currentTimeMillis();
		ftpUtil.ftpUpload("D:/jeecg-framework_v2.1.1-20130130.zip", "image",
				"jeecg-framework_v2.1.1-20130130.zip");
		a = System.currentTimeMillis() - a;
		System.out.println(a);// 6986//1054
	}

	/**
	 * 将一个输入流数据保存到ftp服务器
	 * 
	 * @param input
	 *            本地文件路径包含文件名
	 * @param ftpPath
	 *            所要放于ftp的文件夹
	 * @param newName
	 *            ftp服务器端保存使用的文件名
	 */
	public void ftpUpload(InputStream input, String ftpPath, String newName) {
		FTPClient ftpClient = init();// 初始化
		try {
			// 改变工作目录到所需要的路径下
			boolean isMade = false;
			boolean isChange = false;
			if (ftpPath != null && ftpPath.trim().length() > 0) {
				String[] paths = ftpPath.split("/");
				String newPath = "";
				for (int i = 0; i < paths.length; i++) {
					if (paths[i] != null && paths[i].length() > 0) {
						newPath = newPath + "/" + paths[i];
						isMade = ftpClient.makeDirectory(newPath);
						isChange = ftpClient.changeWorkingDirectory(newPath);
					}
				}
			}

			ftpClient.setBufferSize(1024);
			ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
			ftpClient.storeFile(newName, input);
		} catch (Exception e) {
			System.out.println("Failed to upload!");
			e.printStackTrace();
		} finally {
			try {
				if (input != null) {
					input.close();
				}
				ftpDisConnect(ftpClient);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 从本地将一个文件夹中的文件上传到ftp服务器
	 * 
	 * @param localPath
	 *            本地文件夹
	 * @param ftpPath
	 *            上传的资源所要存放的文件夹
	 */
	public void ftpUploads(String localPath, String ftpPath) {
		FTPClient ftpClient = init();// 初始化
		File uploadFile = new File(localPath);
		File[] fileList = uploadFile.listFiles();
		FileInputStream fis = null;
		if (fileList == null || fileList.length == 0) {
			return;
		}
		for (int i = 0; i < fileList.length; i++) {
			try {
				fis = new FileInputStream(fileList[i]);
				String ftpFileName = fileList[i].getName();
				if (ftpPath != null && ftpPath.trim().length() > 0) {
					ftpClient.makeDirectory(ftpPath);
					ftpClient.changeWorkingDirectory(ftpPath);
				}
				ftpClient.setBufferSize(1024);
				ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
				ftpClient.storeFile(ftpFileName, fis);

			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					if (fis != null) {
						fis.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		ftpDisConnect(ftpClient);
	}

	/**
	 * 文件下载核心代码，下载单个文件和下载一个文件夹中所有文件都会调用这个方法
	 * 
	 * @param ftpPath
	 *            ftp服务器端的文件所在的路径
	 * @param ftpFile
	 *            ftp服务器端的文件名
	 * @param localPath
	 *            客户端保存文件的位置
	 */
	private void downLoadCore(FTPClient ftpClient, String ftpPath,
			String ftpFile, String localPath) {
		if (ftpClient == null)
			ftpClient = init();
		File outfile = new File(localPath + "/" + ftpFile);
		OutputStream fos = null;
		try {
			ftpClient.changeWorkingDirectory(ftpPath);
			FTPFile[] files = ftpClient.listFiles();

			String[] names = ftpClient.listNames();
			List<String> nameArr = Arrays.asList(names);
			if (!nameArr.contains(ftpFile)) {
				return;
			}

			for (FTPFile file : files) {
				if (file.isFile() && file.getName().equals(ftpFile)) {
					fos = new FileOutputStream(outfile);
					ftpClient.setBufferSize(1024);
					ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
					ftpClient.retrieveFile(ftpFile, fos);
				}
			}
		} catch (Exception e) {
			System.out.println("Failed to upload!");
			e.printStackTrace();
		} finally {
			try {
				if (fos != null) {
					fos.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 从ftp服务器下载文件，并将文件写到输出流中
	 * 
	 * @param ftpPath
	 *            ftp服务器端的文件所在的路径
	 * @param ftpFile
	 *            ftp服务器端的文件名
	 * @param output
	 *            指定下载文件的输出流
	 */
	public void ftpDownLoad(String ftpPath, String ftpFile, OutputStream output) {
		FTPClient ftpClient = init();// 初始化
		try {
			// ftpClient.setParserFactory(new OSSFTPFileEntryParserFactory());
			ftpClient.changeWorkingDirectory(ftpPath);
			FTPFile[] files = ftpClient.listFiles();

			String[] names = ftpClient.listNames();
			List<String> nameArr = Arrays.asList(names);
			if (!nameArr.contains(ftpFile)) {
				return;
			}

			for (FTPFile file : files) {
				if (file.isFile() && file.getName().equals(ftpFile)) {
					ftpClient.setBufferSize(1024);
					ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
					ftpClient.retrieveFile(ftpFile, output);
				}
			}
		} catch (Exception e) {
			System.out.println("Failed to upload!");
			e.printStackTrace();
		} finally {
			try {
				if (output != null) {
					output.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			ftpDisConnect(ftpClient);
		}

	}

	/**
	 * 从FTP下载单个文件
	 * 
	 * @param ftppath
	 *            ftp服务器端的文件所在的路径
	 * @param ftpFile
	 *            ftp服务器端的文件名
	 * @param localPath
	 *            客户端保存文件的位置
	 */
	public void ftpDownload(String ftppath, String ftpFile, String localPath) {
		FTPClient ftpClient = init();// 初始化
		downLoadCore(ftpClient, ftppath, ftpFile, localPath);
		ftpDisConnect(ftpClient);
	}

	/**
	 * 从FTP下载一个文件夹
	 * 
	 * @param ftpPath
	 *            ftp服务器端的文件路径（下载那个文件夹下的文件）
	 * @param localPath
	 *            客户端文件的保存路径（下载的文件保存到客户端的那个文件夹里）
	 */
	public void ftpDownloads(String ftpPath, String localPath) {
		FTPClient ftpClient = init();// 初始化
		try {
			ftpClient.changeWorkingDirectory(ftpPath);
			FTPFile[] fileList = ftpClient.listFiles();
			for (int i = 0; i < fileList.length; i++) {
				String ftpFileName = fileList[i].getName();
				File filePath = new File(localPath);
				if (!filePath.exists()) {
					filePath.mkdirs();
				}
				downLoadCore(ftpClient, ftpPath, ftpFileName, localPath);
			}
		} catch (Exception e) {
			e.printStackTrace();
			ftpDisConnect(ftpClient);
		}

	}

	public void ftpDeleteFile(String realpath) {
		int index = realpath.lastIndexOf("/");
		String ftpPath = realpath.substring(0, index);
		String ftpFile = realpath.substring(index + 1);
		ftpDeleteFile(ftpPath, ftpFile);
	}

	public void ftpDeleteFile(String filePath, String fileName) {
		FTPClient ftpClient = init();// 初始化
		try {
			ftpClient.changeWorkingDirectory(filePath);
			ftpClient.deleteFile(fileName);
		} catch (IOException e) {
			System.out.println("Failed to delete");
			e.printStackTrace();
		} finally {
			ftpDisConnect(ftpClient);
		}
	}

	/**
	 * 关闭也ftp服务器的连接
	 */
	public void ftpDisConnect(FTPClient ftpClient) {
		try {
			if (ftpClient.isConnected()) {
				ftpClient.disconnect();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
